#include "widget.h"
#include "ui_widget.h"


#include <QDateTime>
#include <QDebug>
#include <QFileDialog>
#include <QMessageBox>
#include <QTcpSocket>
#include <QTextBlock>
#include <QTimer>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("TcpServer"); //默认为TcpServer后续根据协议类型进行设置
    this->setWindowIcon(QIcon(":/icon/server.png"));
    this->setLayout(ui->horizontalLayout_All);
    TcpServer = new QTcpServer(this);


    sendSize = 0;
    revSize = 0;
    sendType = 0;
    disRev = 0;
    NetworkType = 0;    //协议类型标志位
    btnType = 0;        //按钮类型  监听 / 连接
    getNetworkType();   //设置协议类型
    getHostAddrIp_1();  //获取本机IP地址

    connect(ui->labelSaveDate,&MyLabel::clicked,this,&Widget::OnLabelSaveData);
    connect(ui->labelClearRev,&MyLabel::clicked,this,&Widget::OnLabelClearData);
    connect(ui->labelLoadFile,&MyLabel::clicked,this,&Widget::OnLabelLoadFile);
    connect(ui->labelClearInput,&MyLabel::clicked,this,&Widget::OnLabelClearInput);

    timer = new QTimer(this);
    connect(timer,&QTimer::timeout,[=]()
    {
        on_pushButtonSend_clicked();
    });
    QLayout *Layout = ui->groupBoxInter->layout();
    vLayoutNetworkType = new QVBoxLayout(this);
    vLayoutNetworkType = qobject_cast<QVBoxLayout *>(Layout);


    ///////////////////////////////////////////////////
    // TcpServer 部分
    ///////////////////////////////////////////////////
    stateListen = false;
    connect(TcpServer,&QTcpServer::newConnection,this,&Widget::OnnewConnection);
    ui->comboBox_ClientPort->addItem("All");

    /*  测试每次新的客户端连接就显示新的port在combobox上
     *
        ui->comboBox_ClientPort->insertItem(0,"1000");
        ui->comboBox_ClientPort->setCurrentIndex(0); // 设置为最新插入的项
        ui->comboBox_ClientPort->insertItem(0,"1001");
        ui->comboBox_ClientPort->setCurrentIndex(0);
        ui->comboBox_ClientPort->setCurrentText("1");
    */

    ui->pushButtonSend->setEnabled(false);

    ///////////////////////////////////////////////////
    // TcpClient 部分
    ///////////////////////////////////////////////////
    tcpClient = new QTcpSocket(this);
    stateLink = false;  //客户端的连接状态  开始连接/断开连接 默认为没有连接

    connect(tcpClient,&QTcpSocket::connected,this,&Widget::OnTcpClientconnected);
    connect(tcpClient,&QTcpSocket::disconnected,this,&Widget::OnTcpClientdisconnected);
    connect(tcpClient,&QTcpSocket::readyRead,this,&Widget::OnTcpClientreadyRead);


    connect(TcpServer, &QTcpServer::acceptError, this, [](QAbstractSocket::SocketError socketError) {
        qDebug() << "Server accept error:" << socketError;
    });

    //    connect(tcpClient, &QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred), this, [](QAbstractSocket::SocketError socketError) {
    //        qDebug() << "Client error:" << socketError;
    //    });
}

Widget::~Widget()
{
    delete ui;
}

//获取网络协议类型
void Widget::getNetworkType()
{
    ui->comboBox_PotocolType->addItem("TcpServer");
    ui->comboBox_PotocolType->addItem("TcpClient");
    ui->comboBox_PotocolType->addItem("Udp");
}

//获取IP地址-1.主机信息获取方法
void Widget::getHostAddrIp_2()
{
    //通过QHostInfo的静态函数loaclHostName() 获取到主机的名字
    QString hostName = QHostInfo::localHostName();
    qDebug()<<hostName;

    //通过QHostInfo的静态函数 fromName() 获取到主机信息
    QHostInfo hostInfo = QHostInfo::fromName(hostName);

    //利用主机的成员函数 addresses获取到所有的ip地址
    QList<QHostAddress> hostAddrs = hostInfo.addresses();

    //根据QAbstractSocket中（枚举NetworkLayerProtocol）中的IPv4Protoco筛选出IPv4的地址
    for(QHostAddress hostAddress : hostAddrs)
        if(hostAddress.protocol() == QAbstractSocket::IPv4Protocol)
            qDebug() << hostAddress;

}


//获取IP地址-2.QNetworkInterface获取的方法
void Widget::getHostAddrIp_1()
{

    //通过QNetworkInterface中的静态函数allAddresses() 直接获取到主机的所有IP地址
    QList<QHostAddress> hostAddrs = QNetworkInterface::allAddresses();

    //根据QAbstractSocket中（枚举NetworkLayerProtocol）中的IPv4Protoco筛选出IPv4的地址
    for(QHostAddress hostAddress : hostAddrs)
    {
        if(hostAddress.protocol() == QAbstractSocket::IPv4Protocol)
            ui->comboBox_LoaclHostIP->addItem(hostAddress.toString());
    }

}

void Widget::OnLabelSaveData()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件"),
                                                    "D:/SaveFile.txt",
                                                    tr("Text (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);

    DataItem dataItem;
    for(int i =0;i<HexData.size();i++)
    {
        dataItem = HexData[i];
        out << dataItem._time + dataItem._CStype + dataItem._dataorhexData.toString()+"\n";
    }
    file.close();
}

void Widget::OnLabelClearData()
{
    //a.先是将显示框数据进行删除
    ui->textEdit_DisRev->clear();
    //b.将接收的数据也连同一起删除
    normData.clear();
    HexData.clear();
}

void Widget::OnLabelLoadFile()
{
    ui->textEdit_DisRev->clear();
    QString fileName = QFileDialog::getOpenFileName(this, tr("打开文件"),
                                                    "D:/",
                                                    tr("Text (*.txt)"));
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly| QIODevice::Text))
        return;

    QTextStream in(&file);
    while(!in.atEnd())
    {
        QString inArray;
        inArray = in.readLine();
        ui->textEdit_DisRev->append(inArray);
    }

    file.close();
}

void Widget::OnLabelClearInput()
{
    ui->plainTextEditSend->clear();
}

//newConnection信号对应的槽函数
void Widget::OnnewConnection()
{
    tcpSocket = TcpServer->nextPendingConnection();

    ui->pushButtonSend->setEnabled(true);
    //    qDebug()<<"tcpSocket:"<<tcpSocket;
    //    qDebug()<<"tcpSocket peerPort:"<<tcpSocket->peerPort();         //套接字对应的端口号  客户端端口号
    //    qDebug()<<"tcpSocket localPort:"<<tcpSocket->localPort();       //主机的端口号       服务器端口号

    //    qDebug()<<"tcpSocket: peerAddress"<<tcpSocket->peerAddress();   //套接字对应的IP地址  客户端Ip地址
    //    qDebug()<<"tcpSocket: localAddress"<<tcpSocket->localAddress(); //主机IP地址        服务器IP地址

    hashClients.insert(tcpSocket,tcpSocket->peerPort());

    //combobox显示的都是新连接服务器的端口号
    ui->comboBox_ClientPort->insertItem(0,QString::number(tcpSocket->peerPort()));
    ui->comboBox_ClientPort->setCurrentIndex(0);

    OnTcpServerconnected();//手动调用，防止客户端提前连接了服务器导致没有发送connected信号
    connect(tcpSocket,&QTcpSocket::connected,this,&Widget::OnTcpServerconnected);
    connect(tcpSocket,&QTcpSocket::readyRead,this,&Widget::OnTcpServerReadyRead);
    connect(tcpSocket,&QTcpSocket::disconnected,this,&Widget::OnTcpServerdisconnected);
}


//服务器的connected信号对应的槽函数
void Widget::OnTcpServerconnected()
{
    qDebug()<<"OnTcpServerconnected";

    //这里不可用。。。通过获取信号发送者，执行相应的操作。主要是区别  不同的信号发送者
    //    QList<QTcpSocket *> tcpSockets= TcpServer->findChildren<QTcpSocket *>();
    //    QTcpSocket* tcpSocket = qobject_cast<QTcpSocket *>(sender());
    //所以才创建了一个QTcpSocket* 对象 tcpSocket
    qDebug()<<"tcpSocket:"<<tcpSocket;

    //客户端信息
    QString clientInfo = "客户端的Ip地址:";
    clientInfo += tcpSocket->peerAddress().toString();
    clientInfo += "客户端的端口号:"+QString::number(tcpSocket->peerPort());
    QString name = QString::number(getTcpClientPort(tcpSocket));
    ui->textEdit_DisRev->append("客户端"+name+"已连接："+ clientInfo);
    allText.push_back("客户端"+name+"已连接："+ clientInfo);

}

//获取客户端的数据
void Widget::OnTcpServerReadyRead()
{
    //通过sender（）获取不同客户端发送给服务器的数据
    QTcpSocket* tcpSocket = qobject_cast<QTcpSocket *>(sender());

    QByteArray readInfo = tcpSocket->readAll();
    revSize += readInfo.size();
    QString RevInfo = readInfo;

    QString Port = QString::number(getTcpClientPort(tcpSocket));
    QString name = "[客户端"+Port+"]:";
    QString msg =  name + RevInfo;

    //保存数据
    QString normMsg = RevInfo;
    QByteArray hexMsg = normMsg.toUtf8().toHex();
    saveData(normMsg,getCurTime(),name);
    saveData(hexMsg,getCurTime(),name);

    allText.push_back(msg);
    DataItem dataItem;
    dataItem = normData.back();
    QString timeMsg = dataItem._time + dataItem._CStype +dataItem._dataorhexData.toString();

    if(!ui->checkBox_StopRevDis->isChecked())
    {
        QString msg;
        switch (disRev)
        {
        case 0:
            msg+=name+RevInfo;
            break;
        case 1:
            msg+=timeMsg;
            break;
        case 2:
            msg+=HexData.back()._CStype + hexMsg;
            break;
        case 3:
            msg+=HexData.back()._time+HexData.back()._CStype+hexMsg;
            break;
        }
        appendReceivedMessage(ui->textEdit_DisRev,msg);
        ui->labelRevDataDis->setText("接收："+QString::number(revSize));
    }

}


//服务器。当有客户端断开连接会发送disconnected信号
void Widget::OnTcpServerdisconnected()
{
    resetCuror(ui->textEdit_DisRev);

    //通过sender（）获取不同客户端
    QTcpSocket* tcpSocket = qobject_cast<QTcpSocket *>(sender());

    QString name = QString::number(getTcpClientPort(tcpSocket));
    ui->textEdit_DisRev->append("客户端"+name+"已断开连接");
    allText.push_back("客户端"+name+"已断开连接");
    //客户端断开连接随之combobox的客户端端口号也要去除
    QString delPort = QString::number(tcpSocket->peerPort());
    int index = ui->comboBox_ClientPort->findText(delPort);
    ui->comboBox_ClientPort->removeItem(index);

    //客户端断开连接hashClients中的tcpsocket也要被去除
    hashClients.remove(tcpSocket);
    tcpSocket->deleteLater();
}

//当客户端连接到服务器
void Widget::OnTcpClientconnected()
{
    ui->textEdit_DisRev->append("客户端已连接到服务器");
    allText.push_back("客户端已连接到服务器");
}

//当客户端断开连接
void Widget::OnTcpClientdisconnected()
{
    resetCuror(ui->textEdit_DisRev);
    ui->pushButtonSend->setEnabled(false);

    ui->textEdit_DisRev->append("客户端已经断开连接");
    allText.push_back("客户端已经断开连接");

    ui->pushButton_link->setText("开始连接");

    stateLink=false;
    ui->comboBox_PotocolType->setEnabled(true);
}

//当服务器发来数据
void Widget::OnTcpClientreadyRead()
{
    QByteArray ServerMsg = tcpClient->readAll();
    revSize += ServerMsg.size();
    //保存数据
    QString normMsg = ServerMsg;
    QByteArray hexMsg = normMsg.toUtf8().toHex();
    QString name = "[服务器]:";
    saveData(normMsg,getCurTime(),name);
    saveData(hexMsg,getCurTime(),name);
    allText.push_back(name+normMsg);

    DataItem dataItem;
    dataItem = normData.back();
    QString timeMsg = dataItem._time + dataItem._CStype +dataItem._dataorhexData.toString();

    if(!ui->checkBox_StopRevDis->isChecked())
    {
        QString msg;
        switch (disRev)
        {
        case 0:
            msg+=name+normMsg;
            break;
        case 1:
            msg+=timeMsg;
            break;
        case 2:
            msg+=HexData.back()._CStype + hexMsg;
            break;
        case 3:
            msg+=HexData.back()._time+HexData.back()._CStype+hexMsg;
            break;
        }
        appendReceivedMessage(ui->textEdit_DisRev,msg);
        ui->labelRevDataDis->setText("接收："+QString::number(revSize));
    }

}

//协议类型下拉列表的 选择不同的item
void Widget::on_comboBox_PotocolType_currentIndexChanged(int index)
{
    switch(index)
    {

    //TcpServer
    case 0:
        if(NetworkType == 1 || NetworkType == 2)
        {
            resetSendorRevSize();

            this->setWindowTitle(ui->comboBox_PotocolType->currentText());
            this->setWindowIcon(QIcon(":/icon/server.png"));
            //在垂直布局中移除TcpClient的控件
            vLayoutNetworkType->removeWidget(ui->label_DistanctHostIP);
            vLayoutNetworkType->removeWidget(ui->lineEdit_DistanctHostIP);

            ui->label_DistanctHostIP->hide();
            ui->lineEdit_DistanctHostIP->hide();

            //若是TcpClient界面的控件是隐藏的状态，则将TcpServer需要的控件进行显示出来
            if(ui->label_DistanctHostIP->isHidden())
            {
                ui->label_ClientPort->show();
                ui->comboBox_ClientPort->show();
                ui->label_hostPort->show();
                ui->spinBox_hostPort->show();
            }
            //在垂直布局中指定位置添加TcpServer需要的控件
            vLayoutNetworkType->insertWidget(4,ui->label_hostPort);
            vLayoutNetworkType->insertWidget(5,ui->spinBox_hostPort);
            vLayoutNetworkType->insertWidget(6,ui->label_ClientPort);
            vLayoutNetworkType->insertWidget(7,ui->comboBox_ClientPort);

            ui->pushButton_link->setText("开始监听");
            NetworkType = 0;  //标志位更新
            btnType = 0;
        }
        break;
        //TcpClient
    case 1:
        //将TcpServer 转换为 TcpClient
        if(NetworkType == 0 || NetworkType == 2)
        {
            resetSendorRevSize();
            this->setWindowTitle(ui->comboBox_PotocolType->currentText());
            this->setWindowIcon(QIcon(":/icon/client.png"));
            //在垂直布局中移除TcpServer的控件
            vLayoutNetworkType->removeWidget(ui->label_ClientPort);
            vLayoutNetworkType->removeWidget(ui->comboBox_ClientPort);
            vLayoutNetworkType->removeWidget(ui->label_hostPort);
            vLayoutNetworkType->removeWidget(ui->spinBox_hostPort);

            ui->label_ClientPort->hide();
            ui->comboBox_ClientPort->hide();
            ui->label_hostPort->hide();
            ui->spinBox_hostPort->hide();
            //若是TcpServer界面的控件是隐藏的状态，则将TcpClient需要的控件进行显示出来
            if(ui->label_ClientPort->isHidden())
            {
                ui->label_DistanctHostIP->show();
                ui->lineEdit_DistanctHostIP->show();
            }
            //在垂直布局中指定位置添加TcpClient需要的控件
            vLayoutNetworkType->insertWidget(4,ui->label_DistanctHostIP);
            vLayoutNetworkType->insertWidget(5,ui->lineEdit_DistanctHostIP);
            ui->pushButton_link->setText("开始连接");

            NetworkType = 1;  //标志位更新
            btnType = 1;
        }

        break;

        //Udp
    case 2:
        //TODO...
        this->setWindowTitle(ui->comboBox_PotocolType->currentText());
        break;
    }
}

//客户端端口号，这里可以作为选择不同端口号给不同的客户端发送数据
void Widget::on_comboBox_ClientPort_currentIndexChanged(int index)
{
    switch (index)
    {
    case 0:
//        qDebug()<<"选中了啥"<<index;
        break;
    case 1:
//        qDebug()<<"选中了啥"<<index;
        break;
    case 2:
//        qDebug()<<"选中了啥"<<index;
        break;
    }
}

//可以是 监听  /  连接对应的槽函数
void Widget::on_pushButton_link_clicked()
{

    //不是来回切换，bool类型不适合。
    //TcpServer

    if(btnType == 0)
    {
        //当不是监听状态时，才能进行监听
        if(stateListen == false)
        {
            QHostAddress ip = QHostAddress(ui->comboBox_LoaclHostIP->currentText());
            quint16 port = ui->spinBox_hostPort->text().toUInt();
            if(TcpServer->listen(ip,port))
            {
                resetCuror(ui->textEdit_DisRev);
                ui->textEdit_DisRev->append("**服务器监听中**");

                allText.push_back("**服务器监听中**");
                ui->textEdit_DisRev->append("**服务器地址："+TcpServer->serverAddress().toString());
                allText.push_back("**服务器地址："+TcpServer->serverAddress().toString());
                ui->textEdit_DisRev->append("**服务器端口号："+QString::number(TcpServer->serverPort()));
                allText.push_back("**服务器地址："+TcpServer->serverAddress().toString());
                ui->pushButton_link->setText("停止监听");

                ui->comboBox_PotocolType->setEnabled(false);
                stateListen = true;
            }
            else
            {
                QMessageBox(QMessageBox::Information,"监听失败","服务器监听出错");
                ui->pushButton_link->setText("开始监听");
                return;
            }
        }
        else if(stateListen == true) //当是监听状态时，才能进行停止监听
        {
            //第一种效果，服务器关闭连接，未连接的客户端不能够再进行连接，但是已连接的客户端仍然可以与服务器进行通信。
            //            if(TcpServer->isListening())
            //            {
            //                ui->textEdit_DisRev->append("**服务器已停止监听**");
            //                TcpServer->close();
            //                ui->comboBox_PotocolType->setEnabled(true);
            //                ui->pushButton_link->setText("开始监听");
            //                stateListen = false;
            //            }

            //第二种效果，服务器关闭连接，所有的客户端都与服务器断开连接。不可进行通信


            if(TcpServer->isListening())
            {

                QHash<QTcpSocket*,quint16>::iterator i = hashClients.begin();
                while(i != hashClients.end())
                {
                    i.key()->disconnectFromHost();
                    i.key()->close();
                    i++;
                }

                //                //获取到所以连接服务器的套接字
                //                    QList<QTcpSocket *> tcpSockts = TcpServer->findChildren<QTcpSocket *>();
                //                    //将这些套接字都与服务器断开连接
                //                    for(QTcpSocket* socket : tcpSockts)
                //                    {
                //                        socket->disconnectFromHost();
                //                        socket->close();
                //                    }


                ui->pushButtonSend->setEnabled(false);
                //关闭服务器
                TcpServer->close();

                resetCuror(ui->textEdit_DisRev);

                ui->textEdit_DisRev->append("**服务器已停止监听**");
                allText.push_back("**服务器地址："+TcpServer->serverAddress().toString());
                ui->comboBox_PotocolType->setEnabled(true);
                ui->pushButton_link->setText("开始监听");
                stateListen = false;
            }
        }



    }
    //TcpClient
    else if(btnType == 1)
    {

        //当客户端使未连接状态，才可以进行连接
        if(stateLink == false)
        {
            //通过获取输入框中的服务器的地址和端口号
            QString serverAddrandPort = ui->lineEdit_DistanctHostIP->text();
            if(serverAddrandPort.size() > 0)  //查看输入框是否有输入
            {
                //使用split的到一个QStringList从而分别获得服务器地址 和 端口号
                QStringList Addr_Port = serverAddrandPort.split(':');

                //查看ip地址和端口号是否符合
                bool isAddress = false;
                bool isPort = false;

                if(Addr_Port.count() == 2)
                {
                    isAddress = isValidIPv4(Addr_Port[0].trimmed());
                    isPort = Addr_Port[1].size() == 4;
                }

                if(Addr_Port.count() != 2 || (!isAddress) || (!isPort))
                {
                    //            QMessageBox::Warning(this,"错误信息","服务地址和端口号输入错误");
                    qDebug()<<"Addr_Port.count()"<<Addr_Port.count();
                    qDebug()<<"isAddress"<<isAddress;
                    qDebug()<<"isPort"<<isPort;
                    QMessageBox(QMessageBox::Warning,"错误提示","服务器地址和端口号输入错误").exec();
                    return;

                }
                else   //没有任何错误的情况
                {
                    QByteArray addr = Addr_Port[0].toUtf8(); //地址
                    uint port = Addr_Port[1].toUInt();       //端口号

                    //尝试绑定客户端的IP地址，看服务器显示的客户端地址是否有更改
                    //结果是这样则连不上服务器。
                    //  tcpClient->bind(QHostAddress(ui->comboBox_LoaclHostIP->currentText()));

                    if(tcpClient->state() == QAbstractSocket::ConnectingState)
                    {
                        QMessageBox(QMessageBox::Information,"提示","请勿重复点击,检查服务器是否开启").exec();
                        ui->pushButton_link->setText("开始连接");
                        stateLink = false;
                        ui->comboBox_PotocolType->setEnabled(true);
                        ui->pushButtonSend->setEnabled(false);

                        return;
                    }

                    if(tcpClient->state() == QAbstractSocket::UnconnectedState )
                    {

                        tcpClient->connectToHost(addr,port);

                        ui->pushButton_link->setText("断开连接");
                        stateLink = true;
                        ui->comboBox_PotocolType->setEnabled(false);

                        ui->pushButtonSend->setEnabled(true);

                    }

//                    qDebug()<<tcpClient->state();
                }
            }
            else  //输入框为空
            {
                QMessageBox(QMessageBox::Warning,"错误提示","服务器地址和端口号输入为空").exec();
            }


        }
        //当连接状态是连接状态，才可以进行断开
        else if((stateLink == true) /*&& tcpClient->state() == QAbstractSocket::ConnectedState*/)
        {
            tcpClient->disconnectFromHost();        //从服务器中断开连接

            ui->pushButtonSend->setEnabled(false);
            ui->pushButton_link->setText("开始连接");
            stateLink = false;
            ui->comboBox_PotocolType->setEnabled(true);
        }
    }

//    qDebug()<<tcpClient->state();
}

//发送按钮对应的槽函数
void Widget::on_pushButtonSend_clicked()
{

    //将正常文本和hex文本放在最外层，内部分支就不需要一直重写。
    QByteArray sendMsg = ui->plainTextEditSend->toPlainText().toUtf8();
    sendSize += sendMsg.size();
    QString normData = ui->plainTextEditSend->toPlainText();
    QByteArray hexMsg = NormDataToHexData(normData).toUtf8();
    //TcpServer
    if(btnType == 0)
    {
        //获取TcpServer中的所有QTcpSocket *对象
        QList<QTcpSocket *> tcpServerSockets = TcpServer->findChildren<QTcpSocket *>();

        bool allSend = false;  //发送标志位

        //全部发送
        if(ui->comboBox_ClientPort->currentText() == "All" && (ui->comboBox_ClientPort->count()) > 1)
        {
            allSend = true;   //发送标志位

            for(QTcpSocket* TcpSocket : tcpServerSockets)
            {
                //判断是否是hex发送，给对方的数据
                if(sendType == 2)
                    TcpSocket->write(hexMsg);
                else
                    TcpSocket->write(sendMsg);
            }

            QString name = "[服务器->All客户端]";
            QString msg = ui->plainTextEditSend->toPlainText();


            allText.push_back(name + msg);
            //发送判定to消息展示框
            sendTypeSelect(sendType,name,msg);
            ui->labelSendDataDis->setText("发送："+QString::number(sendSize));
        }

        //选择端口号进行发送
        if(!allSend)
        {
            for(QTcpSocket* TcpSocket : tcpServerSockets)
            {
                if(TcpSocket->peerPort() == ui->comboBox_ClientPort->currentText().toUInt())
                {
                    QString name = "[服务器->客户端"+QString::number(TcpSocket->peerPort())+"]";
                    QString msg = ui->plainTextEditSend->toPlainText();

                    allText.push_back(name+msg);

                    //判断是否是hex发送，给对方的数据
                    if(sendType == 2)
                        TcpSocket->write(hexMsg);
                    else
                        TcpSocket->write(sendMsg);

                    //发送判定to消息展示框
                    sendTypeSelect(sendType,name,msg);
                   ui->labelSendDataDis->setText("发送："+QString::number(sendSize));

                }
            }
        }

    }
    else if(btnType == 1)  //TcpClient
    {
        if(tcpClient->state() == QAbstractSocket::ConnectedState)
        {
            QString name = "[客户端"+QString::number(tcpClient->localPort())+"]";
            QString msg = ui->plainTextEditSend->toPlainText();

            allText.push_back(name+msg);
            //判断是否是hex发送，给对方的数据
            if(sendType == 2)
                tcpClient->write(hexMsg);
            else
                tcpClient->write(sendMsg);
            //发送判定to消息展示框
            sendTypeSelect(sendType,name,msg);
            ui->labelSendDataDis->setText("发送："+QString::number(sendSize));
        }

    }
}


//辅助函数，匹配IP地址是否正确
bool Widget::isValidIPv4(const QString &ip)
{
    QHostAddress address;
    return address.setAddress(ip) && address.protocol() == QAbstractSocket::IPv4Protocol;
}

//辅助函数，获取对应QTcpSocket *sock的端口号
quint16 Widget::getTcpClientPort(QTcpSocket *sock) //不能使用const
{
    //取名
    quint16 tmpPort = 0;
    QHash<QTcpSocket*, quint16>::iterator i = hashClients.find(sock);
    while (i != hashClients.end() && i.key() == sock) {
        tmpPort = i.value();
        ++i;
    }

    return tmpPort;
}





void Widget::on_checkBox_DisRevTime_clicked(bool checked)
{

    ui->textEdit_DisRev->clear();
    bool hexCheckBoxState = ui->checkBox_HexDis->isChecked();
    if(checked)
        disRev+=1;
    else
        disRev-=1;
    if(checked && hexCheckBoxState)
    {
        //        removeLinesWithKeyword(ui->textEdit_DisRev,"[客户端");

        for(int i=0;i<HexData.size();i++)
        {
            QString msg = HexData[i]._time + HexData[i]._CStype + HexData[i]._dataorhexData.toString();
            ui->textEdit_DisRev->append(msg);
        }

    }
    else if(checked &&(!hexCheckBoxState))
    {
        for(int i=0;i<normData.size();i++)
        {
            QString msg = normData[i]._time + normData[i]._CStype + normData[i]._dataorhexData.toString();
            ui->textEdit_DisRev->append(msg);
        }
    }
    else if(hexCheckBoxState)
    {
        for(int i=0;i<HexData.size();i++)
        {
            QString msg = HexData[i]._CStype + HexData[i]._dataorhexData.toString();
            ui->textEdit_DisRev->append(msg);
        }
    }
    else
    {
        for(int i=0;i<allText.size();i++)
        {
            ui->textEdit_DisRev->append(allText[i]);
        }
    }
}

//hex显示
void Widget::on_checkBox_HexDis_clicked(bool checked)
{
    ui->textEdit_DisRev->clear();
    if(checked)
        disRev+=2;
    else
        disRev-=2;
    if(checked && (ui->checkBox_DisRevTime->isChecked()))
    {
        //        removeLinesWithKeyword(ui->textEdit_DisRev,"[客户端");

        for(int i=0;i<HexData.size();i++)
        {
            QString msg = HexData[i]._time + HexData[i]._CStype + HexData[i]._dataorhexData.toString();
            ui->textEdit_DisRev->append(msg);
        }
    }
    else if(checked && (!ui->checkBox_DisRevTime->isChecked()))
    {

        for(int i=0;i<HexData.size();i++)
        {
            QString msg = HexData[i]._CStype + HexData[i]._dataorhexData.toString();
            ui->textEdit_DisRev->append(msg);
        }
    }
    else if(ui->checkBox_DisRevTime->isChecked())
    {

        for(int i=0;i<normData.size();i++)
        {
            QString msg = normData[i]._time + normData[i]._CStype + normData[i]._dataorhexData.toString();
            ui->textEdit_DisRev->append(msg);
        }
    }
    else
    {

        for(int i=0;i<allText.size();i++)
        {
            ui->textEdit_DisRev->append(allText[i]);
        }
    }
}

void Widget::appendReceivedMessage(QTextEdit *textEdit, const QString &message)
{
    QTextCursor cursor(textEdit->textCursor());
    cursor.movePosition(QTextCursor::EndOfBlock); // 移动光标到文档末尾

    // 设置块格式
    QTextBlockFormat blockFormat;
    blockFormat.setAlignment(Qt::AlignLeft); // 左对齐

    // 设置文字样式
    QTextCharFormat charFormat;
    charFormat.setForeground(Qt::black); // 字体颜色
    charFormat.setBackground(QBrush(QColor("#e6f7ff"))); // 背景色
    charFormat.setFontPointSize(10); // 字体大小

    // 获取 QTextEdit 的宽度（内容区域宽度）
    int textEditWidth = textEdit->viewport()->width();
    int midLineWidth = textEditWidth / 2;

    // 使用 QFontMetrics 计算每一段的宽度
    QFontMetrics metrics(textEdit->font());
    QStringList lines;
    QString currentLine;

    // 根据宽度计算换段
    for (const QChar &ch : message)
    {
        currentLine.append(ch);
        if (metrics.horizontalAdvance(currentLine) > midLineWidth)
        {
            lines.append(currentLine); // 当前行超过中线，加入列表
            currentLine.clear();       // 清空，开始新行
        }
    }
    if (!currentLine.isEmpty())
        lines.append(currentLine); // 添加剩余的文字

    // 插入每一行文本
    for (const QString &line : lines)
    {
        cursor.insertBlock(blockFormat);  // 插入块（左对齐）
        cursor.insertText(line, charFormat); // 插入文字
    }

    // 恢复默认样式
    QTextCharFormat defaultCharFormat;
    QTextBlockFormat defaultBlockFormat;

    cursor.setBlockFormat(defaultBlockFormat); // 恢复块格式
    cursor.setCharFormat(defaultCharFormat);   // 恢复字符格式

    textEdit->setTextCursor(cursor); // 应用光标到 `textEdit`
}

void Widget::appendSentMessage(QTextEdit *textEdit, const QString &message)
{
    QTextCursor cursor(textEdit->textCursor());
    cursor.movePosition(QTextCursor::End); // 移动光标到文档末尾

    // 设置块格式
    QTextBlockFormat blockFormat;
    blockFormat.setAlignment(Qt::AlignRight); // 右对齐

    // 设置文字样式
    QTextCharFormat charFormat;
    charFormat.setForeground(Qt::white); // 字体颜色
    charFormat.setBackground(QBrush(QColor("#1890ff"))); // 背景色
    charFormat.setFontPointSize(10); // 字体大小

    // 获取 QTextEdit 的宽度（内容区域宽度）
    int textEditWidth = textEdit->viewport()->width();
    int midLineWidth = textEditWidth / 2;

    // 使用 QFontMetrics 计算每一段的宽度
    QFontMetrics metrics(textEdit->font());
    QStringList lines;
    QString currentLine;

    // 根据宽度计算换段
    for (const QChar &ch : message)
    {
        currentLine.append(ch);
        if (metrics.horizontalAdvance(currentLine) > midLineWidth)
        {
            lines.append(currentLine); // 当前行超过中线，加入列表
            currentLine.clear();       // 清空，开始新行
        }
    }
    if (!currentLine.isEmpty())
        lines.append(currentLine); // 添加剩余的文字

    // 插入每一行文本
    for (const QString &line : lines)
    {
        cursor.insertBlock(blockFormat);  // 插入块（右对齐）
        cursor.insertText(line, charFormat); // 插入文字
    }

    // 恢复默认字符格式,不然会以该富文本块的形式继续后续的数据展示
    QTextCharFormat defaultCharFormat;
    cursor.setCharFormat(defaultCharFormat);
    textEdit->setTextCursor(cursor);
}

QString Widget::getCurTime()
{
    QString curTime ="";
    QDateTime currentDateTime = QDateTime::currentDateTime();

    curTime = QString("%1-%2-%3 %4:%5:%6").arg(currentDateTime.date().year(),2,10,QChar('0'))
            .arg(currentDateTime.date().month(),2,10,QChar('0'))
            .arg(currentDateTime.date().day(),2,10,QChar('0'))
            .arg(currentDateTime.time().hour(),2,10,QChar('0'))
            .arg(currentDateTime.time().minute(),2,10,QChar('0'))
            .arg(currentDateTime.time().second(),2,10,QChar('0'));
    //    qDebug()<<curTime;
    return curTime;
}

void Widget::resetCuror(QTextEdit *textEdit)
{

    // 重置格式为默认样式
    QTextDocument* doc = textEdit->document();

    QTextCursor cursor(doc);
    cursor.movePosition(QTextCursor::End);

    QTextCharFormat defaultCharFormat;
    QTextBlockFormat defaultBlockFormat;

    QTextBlockFormat blockFormat;
    cursor.insertBlock(blockFormat);
    cursor.setBlockFormat(defaultBlockFormat); // 恢复块格式
    cursor.setCharFormat(defaultCharFormat);   // 恢复字符格式



    //    //将新插入的block进行删除
    cursor.removeSelectedText();
    textEdit->setTextCursor(cursor); // 应用光标到 `textEdit`
    //    delEmptyBlocks(textEdit);  //不能将这个空行删除，删除则继续跟着富文本进行显示
}

void Widget::removeBlocks(QTextEdit *textEdit)
{
    QTextDocument *doc = textEdit->document();
    QTextCursor cursor(doc);

    for (QTextBlock block = doc->lastBlock(); block.isValid(); block = block.previous()) {
        bool hasRichText = false;

        // 遍历块内的每个文本片段（QTextFragment）
        for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
            QTextFragment fragment = it.fragment();

            // 获取字符的字体大小
            qreal fontSize = fragment.charFormat().fontPointSize();
//            qDebug() << "Fragment Font Size:" << fontSize;

            // 判断字符的字体大小是否符合富文本标准
            if (fontSize > 0 && fontSize != 9) {  // 假设字体大小9为普通文本
                hasRichText = true;
                break;  // 一旦发现富文本，跳出循环
            }
        }

        // 如果块包含富文本或为空，进行删除操作
        if (hasRichText) {
            cursor.setPosition(block.position());
            cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
//            qDebug() << "Deleting block content:" << cursor.selectedText();
            cursor.removeSelectedText();
            cursor.deleteChar();
        }
    }




}

void Widget::getAllBlocks(QTextEdit *textEdit)
{
    QTextDocument *doc = textEdit->document();
    QTextCursor cursor(doc);
    for (QTextBlock block = doc->firstBlock(); block.isValid(); block = block.next())
    {
        //<<"block text:"<<block.text().trimmed();
        cursor.setPosition(block.position());
        cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
//        qDebug()<<"cursor select:"<<cursor.selectedText();


        if(block.text().isEmpty())
        {
//            qDebug()<<"text isEmpty";/
            cursor.setPosition(QTextCursor::PreviousBlock);
        }
    }
}

void Widget::delEmptyBlocks(QTextEdit *textEdit)
{
    QTextDocument* doc = textEdit->document();
    QTextCursor cursor(doc);

    // 遍历所有块
    for (QTextBlock block = doc->firstBlock(); block.isValid(); block = block.next())
    {
        QString blockText = block.text().trimmed();  // 去除前后空白字符后检查文本
        if (blockText.isEmpty())
        {
            // 如果当前块是空的，删除该块
            cursor.setPosition(block.position());
            cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
            cursor.removeSelectedText();
        }

    }
}

void Widget::sendTypeSelect(int sendtype, QString &name, QString &msg)
{

    switch (sendtype)
    {
    //正常
    case 0:
        appendSentMessage(ui->textEdit_DisRev,name + msg);
        break;
        //发送完自动清空
    case 1:
        appendSentMessage(ui->textEdit_DisRev,name+msg);
        ui->plainTextEditSend->clear();
        break;
        //按十六进制发送
    case 2:
    {
        QByteArray tmp = msg.toUtf8();
        QString hexMsg = tmp.toHex().data();
        appendSentMessage(ui->textEdit_DisRev,name+hexMsg);

    }
        break;
        //自动清空，十六进制发送
    case 3:
    {
        QByteArray tmp = msg.toUtf8();
        QString hexMsg = tmp.toHex().data();
        appendSentMessage(ui->textEdit_DisRev,name+hexMsg);
        ui->plainTextEditSend->clear();

    }
        break;
    }
}

QString Widget::NormDataToHexData(QString &normData)
{
    QByteArray tmp = normData.toUtf8();
    QString hexData = tmp.toHex().data();

    return  hexData;
}

void Widget::resetSendorRevSize()
{
    sendSize = 0;
    revSize = 0;
    ui->labelRevDataDis->setText("接收：0");
    ui->labelSendDataDis->setText("发送：0");
}


template<class T>
void Widget::saveData(T t1, QString time, QString csType)
{
    QByteArray tmp;
    //进行数据类型匹配
    if(typeid (t1) == typeid (tmp))
        HexData.push_back({t1,time,csType});
    else
        normData.push_back({t1,time,csType});
}

void Widget::on_checkBox_NextRow_clicked(bool checked)
{
    if(checked)
    {
        removeBlocks(ui->textEdit_DisRev);
        getAllBlocks(ui->textEdit_DisRev);

        delEmptyBlocks(ui->textEdit_DisRev);
        //        resetCuror(ui->textEdit_DisRev);
    }
}

void Widget::on_checkBox_SendClear_clicked(bool checked)
{
    if(checked)
    {
        sendType += 1;
    }
    else
    {
        sendType -= 1;
    }
}

void Widget::on_checkBox_SendPeriod_clicked(bool checked)
{
    if(checked)
    {
        timer->start(ui->lineEdit_ms->text().toInt());
    }
    else if(timer->isActive())
    {
        timer->stop();
    }
}

void Widget::on_checkBox_HexSend_clicked(bool checked)
{
    if(checked)
    {
        sendType += 2;
    }
    else
    {
        sendType -= 2;
    }
}



void Widget::on_pushButtonReset_clicked()
{
    resetSendorRevSize();
}
